package xiaojian.toolkit.transport.protocol.xip;

import java.util.UUID;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

import xiaojian.toolkit.bean.bytebean.ByteBean;
import xiaojian.toolkit.bean.xip.annotation.SsipField;
import xiaojian.toolkit.bean.xip.core.XipNotify;
import xiaojian.toolkit.bean.xip.core.XipRequest;
import xiaojian.toolkit.bean.xip.core.XipResponse;

//SSIP
//0               1               2               3                
//0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7  
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|  basic ver(1) |                    length(3)                  |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|           srcmodule(2)        |            dstmodule(2)       |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                                                               |
//|                       transaction(16)                         |
//|                                                               |
//|                                                               |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|   type(1)     |                     reserved(3)               |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                           code(4)                             |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|                           data length(4)                      |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
//|application data field(...)                                    |
//|                                                               |
//|                                                               |
//|                                                               |
//+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

//字段名称    字段大小    取值范围    功能说明
//基础协议版本
//(basic ver) 1(byte) [1,255] 标识基础协议的版本号，不会频繁更新，以1为开始版本 xip(1)，tlv(2)，json（3）
//协议包长度
//(length)    3   [32,16777215]   整个协议包长度，最小值为协议头大小(32)，高位字节序
//事务标识
//(transaction)   16  GUID    参照GUID的生成算法，由请求或者通知的发送者保证其在任何时间、地点、平台唯一，请求和响应消息的事物标识必须一致。该标识用于保证请求和响应的唯一对应以及消息的不重复性
//原语类型
//(type)  1   [0,255] 目前支持请求(1)，响应(2)，通知（3），递送(4) 
//保留字段
//（reserved）  3   N/A 基础协议头的保留字段
//消息编码
//（code）  4   [0,2^32]    具体每种消息的编号，建议将对应的请求和响应消息连续编号，高位字节序，按照不同功能进行分组编号。
//消息长度    4   [0,2^32-1]  消息数据域的长度
//协议数据域
//(data field)    n   n/a 唯一对应某个消息编码

/**
 * @author isdom
 * 
 */
public class XipHeader implements ByteBean {
	public static final int SSIP_HEADER_LENGTH = 36;
	public static final int XIP_REQUEST = 1;
	public static final int XIP_RESPONSE = 2;
	public static final int XIP_NOTIFY = 3;

	/**
	 * 默认为2，tlv格式数据。
	 * 
	 * 1 - xip; 2 - tlv; 100 - json
	 */
	@SsipField(index = 0)
	private byte basicVer = 2;

	@SsipField(index = 1, bytes = 3)
	private int length = 0;

	@SsipField(index = 2)
	private short srcModule;

	@SsipField(index = 3)
	private short dstModule;

	@SsipField(index = 4)
	private long firstTransaction;

	@SsipField(index = 5)
	private long secondTransaction;

	@SsipField(index = 6)
	private byte type;

	@SsipField(index = 7)
	private short sourceId;

	@SsipField(index = 8, bytes = 1)
	private int reserved = 0;

	@SsipField(index = 9)
	private int messageCode;

	@SsipField(index = 10)
	private int messageLength;

	/**
	 * @return the basicVer
	 */
	public byte getBasicVer() {
		return basicVer;
	}

	/**
	 * @param ver
	 *            the basicVer to set
	 */
	public void setBasicVer(byte ver) {
		basicVer = ver;
	}

	/**
	 * @return the length
	 */
	public int getLength() {
		return length;
	}

	/**
	 * @param length
	 *            the length to set
	 */
	public void setLength(int length) {
		this.length = length;
	}

	/**
	 * @return the srcModule
	 */
	public short getSrcModule() {
		return srcModule;
	}

	/**
	 * @param module
	 *            the srcModule to set
	 */
	public void setSrcModule(short module) {
		srcModule = module;
	}

	/**
	 * @return the dstModule
	 */
	public short getDstModule() {
		return dstModule;
	}

	/**
	 * @param module
	 *            the dstModule to set
	 */
	public void setDstModule(short module) {
		dstModule = module;
	}

	/**
	 * @return the type
	 */
	public byte getType() {
		return type;
	}

	/**
	 * @param type
	 *            the type to set
	 */
	public void setType(byte type) {
		this.type = type;
	}

	/**
	 * @return the code
	 */
	public int getMessageCode() {
		return messageCode;
	}

	/**
	 * @param code
	 *            the code to set
	 */
	public void setMessageCode(int code) {
		if (code <= 0) {
			throw new RuntimeException("invalid message code.");
		}
		this.messageCode = code;
	}

	/**
	 * @return the messageLength
	 */
	public int getMessageLength() {
		return messageLength;
	}

	/**
	 * g
	 * 
	 * @param length
	 *            the messageLength to set
	 */
	public void setMessageLength(int length) {
		messageLength = length;
	}

	/**
	 * @return the firstTransaction
	 */
	public long getFirstTransaction() {
		return firstTransaction;
	}

	/**
	 * @param firstTransaction
	 *            the firstTransaction to set
	 */
	public void setFirstTransaction(long firstTransaction) {
		this.firstTransaction = firstTransaction;
	}

	/**
	 * @return the secondTransaction
	 */
	public long getSecondTransaction() {
		return secondTransaction;
	}

	/**
	 * @param secondTransaction
	 *            the secondTransaction to set
	 */
	public void setSecondTransaction(long secondTransaction) {
		this.secondTransaction = secondTransaction;
	}

	public void setTransaction(UUID uuid) {
		this.firstTransaction = uuid.getMostSignificantBits();
		this.secondTransaction = uuid.getLeastSignificantBits();
	}

	public UUID getTransactionAsUUID() {
		return new UUID(this.firstTransaction, this.secondTransaction);
	}

	public void exchangeSrcDest() {
		short tmp = this.dstModule;
		this.dstModule = this.srcModule;
		this.srcModule = tmp;
	}

	public void setTypeForClass(Class<?> cls) {
		if (XipRequest.class.isAssignableFrom(cls)) {
			this.type = XIP_REQUEST;
		} else if (XipResponse.class.isAssignableFrom(cls)) {
			this.type = XIP_RESPONSE;
		} else if (XipNotify.class.isAssignableFrom(cls)) {
			this.type = XIP_NOTIFY;
		}
	}

	public String toString() {
		return ToStringBuilder.reflectionToString(this,
				ToStringStyle.SHORT_PREFIX_STYLE);
	}

	/**
	 * @return the sourceId
	 */
	public short getSourceId() {
		return sourceId;
	}

	/**
	 * @param sourceId
	 *            the sourceId to set
	 */
	public void setSourceId(short sourceId) {
		this.sourceId = sourceId;
	}
}
